package com.ben.multiple.shiro;

import com.ben.multiple.shiro.cache.AuthenticationTokenCache;
import com.ben.multiple.shiro.cache.CacheModel;
import com.ben.multiple.shiro.entity.RolePermission;
import com.ben.multiple.shiro.entity.User;
import com.ben.multiple.shiro.entity.UserRole;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.BearerToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * @author Ben
 * @date 2021/1/31
 */
public class CustomRealm extends AuthorizingRealm {
    private final AuthenticationTokenCache authenticationTokenCache;

    public CustomRealm(AuthenticationTokenCache authenticationTokenCache) {
        this.authenticationTokenCache = authenticationTokenCache;
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token != null && BearerToken.class.isAssignableFrom(token.getClass());
    }

    /**
     * 重写 获取 当前用户的权限的方法；在缓存中没查找到数据时，调用此方法。
     *
     * @param principals PrincipalCollection
     * @return AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Object primaryPrincipal = principals.getPrimaryPrincipal();
        User user = (User) primaryPrincipal;
        String username = user.getUsername();
        List<String> roleNameList = UserRole.USER_ROLE_LIST.stream().filter(obj ->
                Objects.equals(obj.getUsername(), username))
                .map(UserRole::getRoleName).collect(Collectors.toList());
        List<String> permissionList = RolePermission.ROLE_PERMISSION_LIST.stream()
                .filter(obj -> roleNameList.contains(obj.getRoleName()))
                .map(RolePermission::getPermission).collect(Collectors.toList());
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setStringPermissions(new HashSet<>(permissionList));
        return authorizationInfo;
    }

    /**
     * 重写 获取 当前登录用户的认证信息的方法；在缓存中没查找到数据时，调用此方法。
     *
     * @param token AuthenticationToken
     * @return AuthenticationInfo
     * @throws AuthenticationException 认证失败
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 请求头中的 token
        String tokens = (String) token.getPrincipal();
        // 从缓存中查找
        CacheModel cacheModel = authenticationTokenCache.get(tokens);
        if (cacheModel == null) {
            return null;
        }
        try {
            User user = new ObjectMapper().readValue(cacheModel.getValue(), User.class);
            return new SimpleAuthenticationInfo(user, tokens, getName());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}
